package cn.lg.soar.activiti.service.impl;

import cn.lg.soar.activiti.service.ModelService;
import cn.lg.soar.common.data.MapPlus;
import cn.lg.soar.common.data.MapPlusWrapper;
import cn.lg.soar.common.util.current.UserContext;
import cn.lg.soar.common.util.data.StringUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
import org.activiti.engine.repository.ProcessDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;

/**
 * @author luguoxiang
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public class ModelServiceImpl implements ModelService {

	private final Logger log = LoggerFactory.getLogger(ModelServiceImpl.class);

	private static final String BPMN20_XML = ".bpmn20.xml";

	private final RepositoryService repositoryService;

	private final ObjectMapper objectMapper;

	public ModelServiceImpl(RepositoryService repositoryService, ObjectMapper objectMapper) {
		this.repositoryService = repositoryService;
		this.objectMapper = objectMapper;
	}

	/**
	 * 创建流程
	 * @param name
	 * @param key
	 * @param desc
	 * @param category
	 * @return
	 */
	@Override
	public Model create(String name, String key, String desc, String category) {
		try {
			ObjectNode editorNode = objectMapper.createObjectNode();
			editorNode.put("id", "canvas");
			editorNode.put("resourceId", "canvas");
			ObjectNode properties = objectMapper.createObjectNode();
			properties.put("process_author", "https://gitee.com/lgx1992/lg-soar");
			properties.put("process_id", key);
			properties.put("name", name);
			editorNode.set("properties", properties);
			ObjectNode stencilset = objectMapper.createObjectNode();
			stencilset.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
			editorNode.set("stencilset", stencilset);

			Model model = repositoryService.newModel();
			model.setKey(key);
			model.setName(name);
			model.setCategory(category);
			model.setVersion(Integer.parseInt(
					String.valueOf(repositoryService.createModelQuery().modelKey(model.getKey()).count() + 1)));

			ObjectNode modelObjectNode = objectMapper.createObjectNode();
			modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name);
			modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, model.getVersion());
			modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, desc);
			model.setMetaInfo(modelObjectNode.toString());
			model.setTenantId(String.valueOf(UserContext.getUser().getCurrentTenantId()));

			repositoryService.saveModel(model);
			repositoryService.addModelEditorSource(model.getId(), editorNode.toString().getBytes("utf-8"));
			return model;
		}
		catch (UnsupportedEncodingException e) {
			log.error("UnsupportedEncodingException", e);
		}
		return null;
	}

	/**
	 * 分页获取流程
	 * @param params
	 * @return
	 */
	@Override
	public IPage<Model> getModelPage(Map<String, Object> params) {
		ModelQuery modelQuery = repositoryService.createModelQuery()
				.modelTenantId(String.valueOf(UserContext.getUser().getCurrentTenantId())).latestVersion()
				.orderByLastUpdateTime().desc();
		String category = (String) params.get("category");
		if (!StringUtil.isBlank(category)) {
			// like '%category%'
			modelQuery.modelCategoryLike("%" + category + "%");
		}

		MapPlus<String> mapPlus = new MapPlusWrapper<>(params);
		int page = mapPlus.getInteger("current");
		int limit = mapPlus.getInteger("size");

		IPage result = new Page(page, limit);
		result.setTotal(modelQuery.count());
		result.setRecords(modelQuery.listPage((page - 1) * limit, limit));
		return result;
	}

	/**
	 * 删除流程
	 * @param ids
	 * @return
	 */
	@Override
	public Boolean removeModelById(String[] ids) {
		for (String id : ids) {
			repositoryService.deleteModel(id);
		}
		return Boolean.TRUE;
	}

	/**
	 * 部署流程
	 * @param id
	 * @return
	 */
	@Override
	public Boolean deploy(String id) {
		try {
			// 获取模型
			Model model = repositoryService.getModel(id);
			ObjectNode objectNode = (ObjectNode) new ObjectMapper()
					.readTree(repositoryService.getModelEditorSource(model.getId()));
			BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(objectNode);

			String processName = model.getName();
			if (!processName.toLowerCase().endsWith(BPMN20_XML)) {
				processName += BPMN20_XML;
			}
			// 部署流程
			Deployment deployment = repositoryService.createDeployment().name(model.getName())
					.addBpmnModel(processName, bpmnModel).tenantId(String.valueOf(UserContext.getUser().getCurrentTenantId()))
					.deploy();

			// 设置流程分类
			List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
					.deploymentId(deployment.getId()).list();

			list.stream().forEach(processDefinition -> repositoryService
					.setProcessDefinitionCategory(processDefinition.getId(), model.getCategory()));
		}
		catch (Exception e) {
			log.error("部署失败，异常", e);
			return Boolean.FALSE;
		}
		return Boolean.TRUE;
	}

}
